﻿using System;
using System.Collections.Generic;
using System.Text;
using ArgusLib.Collections;

namespace ArgusLib.Controls
{
	public class ObjectCollection<T> : IList<T>
	{
		//Dictionary<object, int> keys;
		//List<T> items;
		ListPair<object, T> items;

		public event EventHandler<ItemEventArgs> ItemAdded;
		public event EventHandler<ItemEventArgs> ItemRemoved;

		public IndexedProperty<object, int> Keys { get; private set; }

		public ObjectCollection()
		{
			//this.items = new List<T>();
			//this.keys = new Dictionary<object, int>();
			//this.Keys = new IndexedPropertyGet<object,int>(new IndexedPropertyGet<object,int>.GetHandler((index)=>
			//	{
			//		return this.keys.Keys[
			this.items = new ListPair<object, T>();
			this.Keys = new IndexedProperty<object, int>(new IndexedProperty<object, int>.GetHandler((index) =>
				{
					return this.items.List1[index];
				}), new IndexedProperty<object, int>.SetHandler((index, key) =>
				{
					this.items[index] = new ItemPair<object, T>(key, this.items.List2[index]);
				}));
		}

		bool ICollection<T>.IsReadOnly { get { return false; } }

		public int Count { get { return this.items.Count; } }

		public int GetIndex(object key)
		{
			return this.items.List1.IndexOf(key);
		}

		public T this[int index]
		{
			get { return this.items[index].Item2; }
			set { this.items[index] = new ItemPair<object, T>(this.items[index].Item1, value); }
		}

		public T this[object key]
		{
			get { return this.items[this.GetIndex(key)].Item2; }
			set { this.items[this.GetIndex(key)] = new ItemPair<object, T>(key, value); }
		}

		public void Add(object key, T item)
		{
			this.items.Add(key, item);
			this.OnItemAdded(new ItemEventArgs(this.items.Count - 1, key, item));
		}

		public void Add(T item)
		{
			this.Add(new object(), item);
		}

		public void AddRange(IEnumerable<T> items)
		{
			foreach (T item in items)
				this.Add(item);
		}

		public bool Remove(T item)
		{
			int index = this.items.List2.IndexOf(item);
			if (index < 0)
				return false;
			this.items.RemoveAt(index);
			this.OnItemRemoved(new ItemEventArgs(-1, this.items.List1[index], this.items.List2[index]));
			return true;
		}

		public void RemoveRange(IEnumerable<T> items)
		{
			foreach (T item in items)
				this.Remove(item);
		}

		public void RemoveKeyRange(IEnumerable<object> keys)
		{
			foreach (object key in keys)
				this.RemoveAt(key);
		}

		public void RemoveAt(object key)
		{
			int index = this.GetIndex(key);
			if (index > -1)
				this.RemoveAt(index);
		}

		public void RemoveAt(int index)
		{
			ItemEventArgs e = new ItemEventArgs(-1, this.items.List1[index], this.items.List2[index]);
			this.items.RemoveAt(index);
			this.OnItemRemoved(e);
		}

		public void Insert(int index,object key, T item)
		{
			this.items.Insert(index, key, item);
			this.OnItemAdded(new ItemEventArgs(index, key, item));
		}

		public void Insert(int index, T item)
		{
			this.Insert(index, new object(), item);
		}

		public int IndexOf(T item) { return this.items.List2.IndexOf(item); }

		public void Clear()
		{
			ItemEventArgs[] e = new ItemEventArgs[this.Count];
			for (int i = 0; i < this.Count; i++)
				e[i] = new ItemEventArgs(-1, this.items.List1[i], this.items.List2[i]);
			this.items.Clear();
			for (int i = 0; i < e.Length; i++)
				this.OnItemRemoved(e[i]);
		}

		public bool TryGetValue(object key, out T value)
		{
			int index = this.GetIndex(key);
			if (index < 0)
			{
				value = default(T);
				return false;
			}

			value = this.items.List2[index];
			return true;
		}

		void ICollection<T>.CopyTo(T[] array, int index)
		{
			this.items.List2.CopyTo(array, index);
		}

		public bool Contains(T item) { return this.items.List2.Contains(item); }
		public bool ContainsKey(object key) { return this.items.List1.Contains(key); }

		public Enumerator GetEnumerator() { return new Enumerator(this); }
		IEnumerator<T> IEnumerable<T>.GetEnumerator() { return this.GetEnumerator(); }
		System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return this.GetEnumerator(); }

		protected virtual void OnItemAdded(ItemEventArgs e)
		{
			if (this.ItemAdded != null)
				this.ItemAdded(this, e);
		}

		protected virtual void OnItemRemoved(ItemEventArgs e)
		{
			if (this.ItemRemoved != null)
				this.ItemRemoved(this, e);
		}

		public class ItemEventArgs : EventArgs
		{
			public int Index { get; private set; }
			public object Key { get; private set; }
			public T Item { get; private set; }

			public ItemEventArgs(int index, object key, T item)
			{
				this.Index = index;
				this.Key = key;
				this.Item = item;
			}
		}

		public class Enumerator : IEnumerator<T>
		{
			ObjectCollection<T> collection;
			int index;

			public Enumerator(ObjectCollection<T> collection)
			{
				this.collection = collection;
				this.Reset();
			}

			public void Reset()
			{
				this.index = -1;
			}

			public bool MoveNext()
			{
				this.index++;
				return this.index < this.collection.Count;
			}

			public T Current { get { return this.collection[this.index]; } }
			object System.Collections.IEnumerator.Current { get { return this.Current; } }

			void IDisposable.Dispose() { this.collection = null; }
		}
	}
}
